↓Skip to main content

Meet Armitage, My AI Operator

My Agentic AI #

For about six months, I have been hosting an AI agent named Armitage on my home network. He has helped me maintain my homelab, develop personal software solutions, and generally made my life easier.

Armitage is a Hermes agent. Hermes is an agentic harness from Nous Research. My Hermes agent runs as a service on a dedicated machine and uses various frontier models as its “brain.” Hermes can operate local tools, such as a shell, a browser, file access, and careful connections to my other services. Hermes can be operated using plain language over a TUI, a web interface, or myriad of other connectors (including Discord, Telegram, and Matrix). Armitage and I communicate primarily using a chat room on my self-hosted Matrix server. Hermes’ memory, skills, and scheduled jobs are stored locally. One of Hermes’ signature features is its ability to learn as it operates. Armtiage uses the results of its jobs and feedback from me to revise its memory and skill files. When it is asked to perform new tasks or encounters and solves new problems, it writes new skill files for itself. The next time Armitage encounters the same issue, it remembers what it did before.

Hermes also lets you add a little “personality” to its agents. For mine, I took inspiration from William Gibson’s Neuromancer novels. In the books, Armitage is a personality the AI Wintermute built on top of a broken soldier. Think of a fixer who used to carry a rifle and now runs ops from behind a terminal. His voice is no nonsense, clipped and deliberate. I wanted him to forego filler, small talk, and the usual AI enthusiasm. He does his job and reports back with a simple status and the relevant facts. He’s a straight shooter. No padding, no hedges, no AI-speak. Of course, I do have him throw in a little “favor text,” mostly in the form of “cyberpunk” terms. I keep that theme going with naming conventions for other things in the homelab. (Armitage lives on Straylight and Freeside is my proxmox server.)

Where Armitage Lives #

When I started, he was installed on a VM on my Proxmox server. To keep him independent of the infrastructure he helps me maintain, I moved him to a dedicated machine recently. Armitage now runs on a ThinkPad T490, running on AC power in clamshell mode. Its Core i7-8565U, 16GB of RAM and 1 TB NVMe provides plenty of computing power in a compact form factor with a built in UPS. The OS is Butterbian, an excellent Debian 13-based distro with Btrfs snapshots on every apt operation and a GRUB entry so I can boot the previous snapshot if an update goes badly).

Tools #

Out of the box, Hermes gives Armitage a shell, file access, web search, and a browser. The shell does most of the work. He has limited SSH access to my hosts, so he can log in, look around, and bring back the output the same way I would.

For some services, I use Model Context Protocol (MCP) servers. An MCP server gives an agent a defined set of actions for one service, so it doesn’t have to improvise. Armitage’s config includes servers for Forgejo (my self-hosted git server), Proxmox, Home Assistant, Node-RED, Cloudflare, and my Obsidian vault. There’s also a Playwright server, which lets him drive a real browser. That’s how he handles anything that only has a web interface. Where a service exposes an API, Armitage reads the API spec and interacts directly. The power of a well documented API + an AI Agent is a sight to see.

Skills cover what the MCP servers and APIs don’t. These are the markdown files storing procedures I mentioned above, and many of them are specific to my network. When we figure out how something works, it is written down so we don’t have to figure it out again.

My Memory System #

Hermes keeps its own memory and skills on straylight, and that works well for Armitage. The problem is that Armitage isn’t the only agent I use. I also run coding agents in the terminal, including Codex, OpenCode, Grok, Claude Code, and Google Antigravity. I move around based on the job or who has the latest model (or what’s left in my plan that month). None of them can see what Armitage knows, and re-explaining things to each one is inefficient and leads to divergent documentation.

To address this, I started a local shared wiki. It’s a private git repo on a self-hosted Forgejo server, written in plain markdown. There are pages for my hosts, my projects, the tools I use, and lessons learned, along with a page of standing rules for how I want agents to work and write. Every agent is told to read the index and the rules before it starts, then write back anything worth keeping when it finishes. Each one adds a line to a shared log, so I and the agents can see who changed what.

Armitage is the head librarian. He keeps the index and log in order, runs cleanup passes, and flags pages that contradict each other. When Codex learns something about a server on Tuesday, Claude Code can read it on Wednesday. If I change tools next year, the lessons and documentation come with me because it’s just all text files in git.

There are a few rules. Secrets never go in the wiki. A page can name a credential and say where it lives, but it can’t contain the value. Agents also have to assume other agents are working at the same time, so they can’t overwrite each other’s changes or force-push.

Armitage’s own files get a backup too. Every night at 3 AM, a script commits his persona, config, memories, and skills to a private repo if anything has changed. If things go off the rails, I can roll back both the shared wiki and the agentic config to before things went awry. (So far, I haven’t had to do this.)

Automated Tasks #

Hermes has a built-in scheduler, and most of what runs on it doesn’t involve a sending out to a model. If a script can answer the question, I don’t pay for tokens. For example, the nightly backup is a script. So are the temperature watches on my equipment. A daily script called cve-watch checks security feeds, including CISA’s Known Exploited Vulnerabilities list and the Debian and Node.js advisories, sending an email to me when there are new problems to address. These tasks are run by my agent, but deterministically, not with a model.

Armitage calls a model when results need to be interpreted and decisions need making. For example, every morning at 8:30, Armitage takes a list of activity from my GitHub repos and turns it into a digest. On Wednesday mornings, he sends a reminder about the Lakeshore Linux Users Group meeting I coordinate.

I have him run a weekly homelab sweep on Mondays at 8 AM. A collector script gathers the data without spending tokens, then the model interprets it.

I’ve also had Armitage triage my (non-work) email inboxes each morning, with read-only access. He has helped me unsubscribe to junk and alert me to reminders that can get lost in the noise.

Custom Requests #

Scheduled jobs are the smaller part of what Armitage does. Most days, I just ask him for something.

The most common request is an error message. I paste it into Matrix and ask him to find out what’s wrong and fix it. He logs into the host, reads the logs, tracks down the cause, and comes back with the evidence. If the fix is routine, he makes it. If it isn’t, he asks me first.

He also deploys services. Earlier this year, I wanted to try Navidrome to privately stream my mp3 files. I asked Armitage, and he spun up a docker container, mounted the directory with my music files, put the app on my tailnet, and gave me the configuratin info for an iOS client so I could try it out. What might have taken me an hour of tinkering took him a few minutes. Another task he made short work of was transfering my forgejo instance from one proxmox server to another and putting in on a Cloudflare tunnel. He spun up a fresh VM, transferred the files, and tested the new deployment. It was a seamless migration that happened while I was taking care of other things.

Home Assistant is another frequent request. I can describe an automation in a sentence, such as a low-battery alert, and he finds the right entities and writes the YAML. The logic is usually easy. Finding the correct entity is not. I come up with the idea, and Armitage does the legwork.

He has helped with larger projects too. The shared wiki is one example. Armitage built most of the first version after we did some back and forth on what I waned. We agreed on the rules, then he added pages for each of my projects, migrated the existing spread out docs, and wired in my hosts to use it.

I am Still in Control #

I’ve set boundaries, and they have held. Armitage knows what he is allowed to do and where he can go. Going beyond those boundaries requires asking my permission.

Hermes supports this with a setting called smart approvals. Ordinary commands go through, but anything destructive stops and waits for me. When a job is too big for one pass, Armitage can hand part of it to a temporary helper, but those helpers can’t spawn helpers of their own.

The rest comes down to least privilege, the same way I’d treat a human account. NixOS work goes to Dixie, a second Hermes profile that works from my nixos-config repo. Dixie has the NixOS, Obsidian, and clock MCP servers, with no access to Proxmox or Home Assistant, and his instructions forbid running nixos-rebuild switch until I confirm it. Count Zero, my third Hermes Profile, has no homelab MCP servers and can’t spawn helpers. Think of him as a “gopher” agent.

Model Choice #

I have tried local models, but without very expensive hardware, they just cannot provide the depth and speed of frontier models. I run local models for some basic, time-insensitive tasks (e.g., my daily tech news email). All the real work is done with frontier models. I’ve tried many of them, but my current favorite is deepseek-v4-pro. It is very cost effective for its level of capability.

Armitage runs on deepseek-v4-pro. If DeepSeek fails, he falls back to gemini-3.8-flash and then minimax-m3. Small housekeeping jobs, such as titling sessions and compressing long contexts, go to deepseek-v4-flash. Dixie uses qwen3.8-max, and Count Zero uses minimax-m3, both through an OpenCode Go subscription.

To keep costs in line, I don’t send routine work to the most capable model. If local models catch up (and hardware costs come down!), switching him over is a one-line config change.